#include "parafluidsmoothingkernel.h"
#include "parafluidsphdensity.h"
#include "parafluidsphneighbor.h"

using namespace ParaFluid;

DensityUpdater::~DensityUpdater()
{
	/* does nothing */
}

DensityUpdater::DensityUpdater()
	: AtomVoxelizer::ReadWriteVisitor()
	, _SPH(0)
{
	/* does nothing */
}

void DensityUpdater::updateDensity(SPH & sph)
{
	_SPH = &sph;
	_SPH->atomVoxelizer.acceptVisitor(*this);
}

void DensityUpdater::updateDensityParallel(SPH & sph, int indexFirst, int indexLast)
{
	_SPH = &sph;
	_SPH->atomVoxelizer.acceptVisitor(*this, indexFirst, indexLast);
}

void DensityUpdater::visit(Atom & atom)
{
	atom.currentDensity = 0;
	
	class DensityAccumulator
		: public NeighborhoodReadOnlyVisitor
	{
		
	private:
		
		SPH * _SPH;
		
		Atom * _atom;
		
	public:
		
		~DensityAccumulator()
		{
			/* does nothing */
		}
		
		DensityAccumulator(SPH & sph, Atom & atom)
			: NeighborhoodReadOnlyVisitor()
			, _SPH(&sph)
			, _atom(&atom)
		{
			/* does nothing */
		}
		
		void visitNeighbor(const Atom & neighbor)
		{
			_atom->currentDensity += SmoothingKernel::valuePoly6(_SPH->smoothingDistance(), _atom->currentPosition.distanceTo(neighbor.currentPosition)) * neighbor.substance.mass;
		}
		
	} accumulator(*_SPH, atom);
	
	accumulator.visitNeighborhood(*_SPH, atom);
}
